Repository navigation
Experiment design identity and counts: excluded folders, duplicate columns, output folder (#82, #83, #98) - #130
Merged
Merged
Conversation
A technical-repeat folder whose images are all excluded was still counted in BiologicalRepeat.technical_repeat_count, the balance table and the design's technical_repeat_count. It is no longer counted, and the balance text (CLI check, notebook consistency and design cards) says how many images were excluded and names the folders not counted. A folder named single keeps plan question 23's meaning (documented only). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
#83) Every design reader (read_experiment_design, so load_design, the notebook, check, run --design and the design command, and read_confirmed_design) refuses a header that names a column twice, ignoring case and outer whitespace, or has a column without a name, with DesignFormatError naming the column and its positions. The lenient reader kept the last of two columns before, and a test asserted it; that test now asserts the refusal. RunInputs.design() reads with read_confirmed_design against the manifest's SHA-256 instead of the lenient reader. The header check and the value parsers move to design_values (pure), so design.py shrinks (964 -> 926 lines) and the baseline loses the _count entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
The design confirmed for one output folder was kept when the output folder changed, and the run wrote it, with its confirmations and controls, into the new folder. Now the design belongs to its output folder: a change reads the design saved in the new folder (an unreadable one refused and kept), or asks the questions again when there is none. Nothing is carried over and nothing is written until an answer, so a folder typed one character at a time creates nothing; the design card says which happened. The widget tests are in a new test file (test_notebook_ui.py is over the size limit); design_tree moves to tests/tiff_tree.py so both share it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
# Conflicts: # docs/plan.md # src/morphobricks_preprocessing/run_inputs.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
guijacquemet
marked this pull request as ready for review
November 2, 2026 17:26
…failing Setting the notebook's output folder to a path under a file (somefile/out) raised an uncaught NotADirectoryError from the run step's refresh (_planned_masks -> current_fingerprint -> source_fingerprint), and a run click failed with "unexpected problem". current_fingerprint now treats a path under a file as gone; the output hint names the file in red, the design is not saved there, and step 3 waits for another output folder. Regression test in test_notebook_design_output.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
…cter (#83) The header check compared names ignoring case and outer whitespace only, so a second column written with a byte-order mark or zero-width space inside the file ("condition", "Condition") looked new and the lenient reader (load_design, notebook step 1, check, run --design, design) silently read the first one. Invisible format characters (Unicode Cf) are now ignored when comparing, and a column of only such characters has no name. Tests in test_confirmed_design.py; plan Q63 and contract §12. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
No conflicts; plan questions on main end at 59, so 62-64 are renumbered once #128 and #129 land. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
docs/plan.md §12: main's question 60 (#129, OME-Zarr axes and calibration) is kept, and this PR's questions 62-64 become 61-63 so the numbers are unique and sequential; the references in contract §9.1, §11, §12 and plan §10 follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Contributor
Author
Independent review: merged as feec007 (merge commit, head f7257b7)Findings fixed on the branch
Each "Fixes" claim checked in the code with adversarial probes
Gate (own worktree, uv venv, Python 3.11,
§9 figures (measured on the touched functions)
Issues #82, #83 and #98 closed automatically when this merged. The branch was auto-deleted and I restored it at f7257b7. Generated by Claude Code |
guijacquemet
pushed a commit
that referenced
this pull request
Nov 2, 2026
Conflicts resolved hunk by hunk: - docs/plan.md: main's "Before the audit" entry (#82, #83, #98) kept, then PP-12's; main's questions 61 to 63 kept and PP-12's question renumbered 64. - run_inputs.py RunInputs.design(): main's strict read_confirmed_design, on the file PP-12's published_path names (the current generation's design). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
guijacquemet
pushed a commit
that referenced
this pull request
Nov 2, 2026
Plan §12: main's questions 61-63 (#130) kept; this PR's link and log questions renumbered 64 and 65 (owner, 2 November 2026), and the plan's done-list entry with them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
guijacquemet
pushed a commit
that referenced
this pull request
Nov 2, 2026
Conflicts: plan questions (main has 60 to 63; this branch's questions become 66 and 67, 64 and 65 being taken by #128) and the code-rule layers of pyproject.toml (size_checks and ngff_scale, both pure). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
guijacquemet
pushed a commit
that referenced
this pull request
Nov 2, 2026
The test asserted the old status 0 for a refused design that 'check' prints as an error; the new status is 1, as 'run' gives for the same design. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
This was referenced Nov 2, 2026
Merged
Links stay inside the experiment and masks folders; --log is checked before it opens (#81, #99)
#128
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #82, Fixes #83, Fixes #98.
Before-audit batch (triage
docs/restart/triage-preprocessing-2026-11-02.md, bucket A). Binding: design v0.4 §3, §6, §9. Each claim below was reproduced by a test that fails onmain(6ac81ad, after #126) and passes here.Summary (by module)
#82: technical-repeat counts (
dataset.py,report.py,notebook_render.py,notebook_design.py)biological_repeats()counted every technical-repeat folder, also one whose images were all excluded (dataset.py ~180). It now counts only folders with at least one image to analyse, soBiologicalRepeat.technical_repeat_count, the balance table and the design'stechnical_repeat_countare right (ctrl/rep1/techA+techBwithtechB's only image excluded: 1 technical repeat, not 2).BalanceTablegainsexcluded_images,excluded_foldersandnot_counted(). The CLIcheckbalance text, the notebook's consistency card and its design card say how many images were excluded and name the folders not counted.singlepart follows plan Q23 and is only documented: a technical-repeat folder namedsingleis the level's valuesingleand counts as no technical-repeat folder, like a missing level. There is a test for it, and the behaviour is unchanged.#83: duplicate design columns (
design.py, newdesign_values.py,run_inputs.py)read_experiment_design(and soload_design, notebook step 1,check,run --designand thedesigncommand) andread_confirmed_design. Names are compared ignoring case and outer whitespace. TheDesignFormatErrornames the column and both positions, for example:the header names the column 'repeat_group' twice (columns 3 and 10), so it is not clear which value to read. Delete one of the two columns.Before this, the lenient reader kept the last column. The test that asserted that now asserts the refusal, with both conflicting and equal values. Nothing is rewritten on refusal: there are tests forload_designand fordesign --confirm-all.RunInputs.design()now reads withread_confirmed_design(path, expected_sha256=manifest.experiment_design_sha256)instead of the lenient reader. Any refusal becomes aRunInputsError, with the refusal as its__cause__. The SHA-256 is now taken from the bytes that are parsed, not from a separate hash followed by a second read.parse_bool,parse_count,is_date,DATE_FORMAT,DesignFormatError) move todesign_values.py(pure).designre-exports them under the same names. The two readers share_check_rows(folder listed twice,controldisagreeing).DesignFormatError.__module__is nowmorphobricks_preprocessing.design_values.#98: output folder change (
notebook_folder.py,notebook_design.py,notebook_ui.py)_output_editedused to keepself.design, so the run wrote the old folder's confirmed design and controls into the new folder. Now, when the design card is open and the output folder resolves to another folder, the design is loaded again with_open_design(output_changed=True):Tests
tests/test_notebook_design_output.py.test_notebook_ui.pyis already over the size limit, so the new widget tests go here;design_treemoves totests/tiff_tree.pyand both files share it.tests/test_dataset.py,tests/test_confirmed_design.py,tests/test_run_inputs.py.Decisions (recorded in plan §12, renumbered 61–63 at the merge of #129)
singlestays as Q23 says, documented only.RunInputs.design()reads strictly.Review fixes (independent review)
\ufeffconditionorCondition\u200b(a byte-order mark or zero-width space inside the header) looked new and the lenient reader (load_design, notebook step 1,check,run --design,design) silently read the first one. Invisible format characters (UnicodeCf) are now ignored when comparing, and a column of only such characters has no name. Plan Q62 and contract §12 say so; 3 new parametrized cases fail on the previous head.somefile/outraised an uncaughtNotADirectoryErrorfrom the run step's refresh, and a run click showed "unexpected problem".current_fingerprinttreats a path under a file as gone; the output hint names the file in red; the design is not saved there; step 3 waits ("choose an output folder that is not a file"). Regression testtest_an_output_folder_under_a_file_is_refused_with_a_message(fails on the previous head). User guide §4 step 1.Tests failing on
main16 regression tests fail with
main'ssrcand pass here:test_dataset.py, plus the design-card test intest_notebook_design_output.py.test_confirmed_design.py(5 parametrized duplicate or unnamed header cases, plus thedesigncommand test), the updated'condition' twicemessage case, andtest_run_inputs.py::test_the_design_is_read_with_the_strict_reader.test_notebook_design_output.py: A to B to A with conflicting controls, a new empty folder typed character by character, and an unreadable design in the new folder.The later locked-folder test (save failure) was not run against
main.Full gate (local, Python 3.11,
.[dev,notebook,zarr], zarr 3.1.6)ruff check .: all checks passed.ruff format --check .: 179 files already formatted.pytest: 1797 passed, 1 skipped (implementer); review, after merging main (PP-11b: the notebook's Make named-axis copies card #127, OME-Zarr axes and calibration: nothing guessed, nothing silent (#72, #73, #94) #129): 1852 passed, 1 skipped (skip as root, expected). The skip istest_discovery.py:665, "running with permissions that ignore file modes", which is expected because the run is as root.python tools/check.py --rules: exit 0.§9 figures (measured)
design.py _countremoved).design.py: 964 → 926 lines.test_notebook_ui.py: 1537 → 1529.design_values.pyhas 105 lines and is declaredpurein pyproject.test_notebook_design_output.pyhas 162 lines.dataset.py377,notebook_design.py454,notebook_folder.py406,run_inputs.py592 lines.# noqacounts unchanged (ANN 54, PLR0913 3, C901 0, PLR0915 0). Totalnoqain*.pyis unchanged at 124: one E402 line was edited, none added.Notes for review
mainwas merged in (the PP-11c: conversion integrity (copy SHA-256, metadata epochs, exact CLI sizes) #126 conversion PR); the one conflict was in therun_inputs.pyimport lines. Not rebased.https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Generated by Claude Code